home *** CD-ROM | disk | FTP | other *** search
/ Amiga Developer CD 2.1 / Amiga Developer CD v2.1.iso / CDTV / cdtvtools-11 / keeper / ilbm.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-06-24  |  8.0 KB  |  361 lines

  1. /****************************************************************************
  2.  
  3.   ilbm.c -- routines to read IFF.ILBM files written by Ray Lambert
  4.   These routines are public domain
  5.  
  6. ****************************************************************************/
  7.  
  8. #include <stdio.h>
  9. #include "keeper.h"
  10. #include <exec/memory.h>
  11. #include <hardware/blit.h>
  12. #include <hardware/custom.h>
  13. #include <proto/dos.h>
  14. #include <proto/exec.h>
  15. #include <proto/graphics.h>
  16.  
  17.  
  18. /*
  19. **  IFF.ILBM stuff...
  20. */
  21. struct BitMapHeader
  22. {
  23.   UWORD w,h;
  24.   WORD  x,y;
  25.   UBYTE nPlanes;
  26.   UBYTE masking;
  27.   UBYTE compression;
  28.   UBYTE pad1;
  29.   UWORD transparentColor;
  30.   UBYTE xAspect,yAspect;
  31.   WORD  pageWidth,pageHeight;
  32. };
  33.  
  34. /*
  35. **  compression types
  36. */
  37. #define cmpNone      0
  38. #define cmpByteRun1  1
  39.  
  40. /*
  41. **  info to identify a mask
  42. */
  43. #define mskNone                 0
  44. #define mskHasMask              1
  45. #define mskHasTransparentColor  2
  46. #define mskLasso                3
  47.  
  48. /*
  49. **  IFF.ILBM chunk names
  50. */
  51. #define MakeID(a,b,c,d) ((a)<<24|(b)<<16|(c)<<8|(d))
  52. #define FORM  MakeID('F','O','R','M')
  53. #define ILBM  MakeID('I','L','B','M')
  54. #define BMHD  MakeID('B','M','H','D')
  55. #define CMAP  MakeID('C','M','A','P')
  56. #define CAMG  MakeID('C','A','M','G')
  57. #define BODY  MakeID('B','O','D','Y')
  58.  
  59.  
  60.  
  61. /*
  62. **  Copy from 'src' to 'dst' -- 'dst' must receive 'rowlen' bytes --
  63. **  bytes at 'src' may be compressed -- 'comp' indicates if compression
  64. **  was used and if so what type -- returns the number of bytes read
  65. **  from 'src' -- 'src' may be 0 and if so 'rowlen' zero bytes are placed
  66. **  in 'dest' regardless of 'comp' -- 'dst' may be 0 and if so no bytes
  67. **  are actually stored but 'src' is treated normally, allowing the caller
  68. **  to determine how many 'src' bytes to skip in case 'src' is compressed
  69. */
  70. static ULONG copy_line(UBYTE *src, UBYTE *dst, UBYTE comp, ULONG rowlen)
  71. {
  72.   register ULONG cnt;
  73.   register signed char b;
  74.  
  75. /*
  76. **  no source data - fill "dst" with "rowlen" zero bytes
  77. */
  78.   unless( src )
  79.     {
  80.       memset(dst,0,rowlen);
  81.       return(0);
  82.     }
  83.  
  84. /*
  85. **  no compression used - just do a direct copy
  86. */
  87.   if (comp == cmpNone)
  88.     {
  89.       if (dst) memcpy(dst,src,rowlen);
  90.       return(rowlen);
  91.     }
  92.  
  93. /*
  94. **  data is compressed -- expand "rowlen" number of bytes
  95. **  "cnt" counts the number of bytes read from "src"
  96. **  "rowlen" counts-down the number of bytes to put into "dst"
  97. */
  98.   cnt = 0;
  99.   while(rowlen > 0)
  100.     {
  101.       b = *src;
  102.       src++;
  103.       cnt++;
  104.       if (b == -128) continue;
  105.  
  106.       if (b >= 0)
  107.         {
  108.  
  109.         /*
  110.         **  copy "b" + 1 bytes directly
  111.         */
  112.           b++;
  113.           if (rowlen < b) b = rowlen;
  114.           rowlen -= b;
  115.           if (dst)
  116.             {
  117.               memcpy(dst,src,b);
  118.               dst += b;
  119.             }
  120.           src += b;
  121.           cnt += b;
  122.         }
  123.       else
  124.         {
  125.  
  126.         /*
  127.         **  replicate byte at "src" (abs(b) + 1) times
  128.         */
  129.           b = ( abs(b) + 1 );
  130.           if (b > rowlen) b = rowlen;
  131.           rowlen -= b;
  132.           if (dst)
  133.             {
  134.               memset(dst,*src,b);
  135.               dst += b;
  136.             }
  137.           src++;
  138.           cnt++;
  139.         }
  140.  
  141.     }
  142.  
  143.   return(cnt);
  144. }
  145.  
  146.  
  147.  
  148. /*
  149. **  Load the BODY data from an ILBM file
  150. */
  151. static BOOL loadBODY(BPTR file, ULONG len, struct BitMapHeader *bmhd,
  152.                       struct BLITmap *bm)
  153. {
  154.   ULONG
  155.     rowlen,
  156.     cnt,
  157.     pcnt;
  158.   PLANEPTR
  159.     body,
  160.     b,
  161.     p[8];
  162.  
  163. /*
  164. **  calculate number of bytes in one row
  165. */
  166.   rowlen = ( ( (bmhd->w + 15) / 16 ) * 2 );
  167.  
  168. /*
  169. **  allocate memory for each plane
  170. */
  171.   for(pcnt = 0; pcnt < bmhd->nPlanes; pcnt++)
  172.     unless( bm->p[pcnt] = p[pcnt] = AllocRaster(bmhd->w,bmhd->h) )
  173.       return(FALSE);
  174.  
  175. /*
  176. **  allocate memory to load body chunk into
  177. */
  178.   unless( b = body = AllocMem(len,0) ) return(FALSE);
  179.  
  180. /*
  181. **  read the BODY chunk into memory
  182. */
  183.   unless( Read(file,body,len) == len )
  184.     {
  185.       FreeMem(body,len);
  186.       return(FALSE);
  187.     }
  188.  
  189. /*
  190. **  expand interleaved BODY chunk into seperate planes
  191. */
  192.   for(cnt = 0; cnt < bmhd->h; cnt++)
  193.     {
  194.  
  195.     /*
  196.     **  use "copy_line()" to expand a single line into each plane
  197.     */
  198.       for(pcnt = 0; pcnt < bmhd->nPlanes; pcnt++)
  199.         {
  200.           b += copy_line(b, p[pcnt], bmhd->compression, rowlen);
  201.           p[pcnt] += rowlen;
  202.         }
  203.  
  204.     /*
  205.     **  skip the mask data line (if there is any)
  206.     */
  207.       if (bmhd->masking == mskHasMask)
  208.         {
  209.           b += copy_line(b, 0, bmhd->compression, rowlen);
  210.         }
  211.  
  212.     }
  213.  
  214. /*
  215. **  free the temporary buffer used for the BODY chunk
  216. */
  217.   FreeMem(body,len);
  218.  
  219. /*
  220. **  all's well that ends well
  221. */
  222.   return(TRUE);
  223. }
  224.  
  225.  
  226.  
  227. /*
  228. **  load a CMAP chunk and pack it into an Amiga color map (palette)
  229. */
  230. static BOOL loadCMAP(BPTR file, ULONG len, UWORD *cmap)
  231. {
  232.   UBYTE rgb[3*32];  /* buffer to read raw RGB bytes from file */
  233.   ULONG cnt;
  234.  
  235.   cnt = min(len,sizeof(rgb)); /* don't load more than 'rgb' can hold */
  236.   unless( Read(file,rgb,cnt) == cnt ) return(FALSE);
  237.   if (len > cnt) Seek(file,(len-cnt),OFFSET_CURRENT); /* skip unused bytes */
  238.   cnt /= 3; /* number of colors for CMAP (triplets of bytes in 'rgb') */
  239.   PackCMAP(rgb,cmap,cnt);
  240.   return(TRUE);
  241. }
  242.  
  243.  
  244.  
  245. /*
  246. **  load an IFF.ILBM picture from disk
  247. */
  248. struct BLITmap *loadILBM(char *name)
  249. {
  250.   BPTR file;
  251.   ULONG type, len;
  252.   struct BitMapHeader bmhd;
  253.   struct BLITmap *bm;
  254.  
  255.   unless( bm = (struct BLITmap *)AllocMem(sizeof(struct BLITmap),MEMF_CLEAR) )
  256.     return(0);
  257.   unless( file = Open(name,MODE_OLDFILE) )
  258.     {
  259.       FreeMem(bm,sizeof(struct BLITmap));
  260.       return(0);
  261.     }
  262.  
  263.   unless( (Read(file,(UBYTE *)&type,4) == 4) && (type == FORM) )
  264.     {
  265. enderr:
  266.       Close(file);
  267.       if (bm) unloadILBM(bm);
  268.       return(0);
  269.     }
  270.   unless( Read(file,(UBYTE *)&len,4) == 4 ) goto enderr;  /* FORM length */
  271.   unless( (Read(file,(UBYTE *)&type,4) == 4) && (type == ILBM) ) goto enderr;
  272.  
  273.   memset(bm->cmap,0,sizeof(bm->cmap));  /* clear the CMAP in case none in file */
  274.   bm->modes = 0;  /* clear the modes in case none in file */
  275.   bmhd.w = 0;     /* flag if a BMHD chunk has been found  */
  276.  
  277.   until(6==9)
  278.     {
  279.       unless( Read(file,(UBYTE *)&type,4) == 4) goto enderr; /* chunk type */
  280.       unless( Read(file,(UBYTE *)&len,4) == 4) goto enderr;  /* chunk length */
  281.  
  282.       switch(type)
  283.         {
  284.           case BMHD:
  285.             {
  286.               unless( len == sizeof(struct BitMapHeader) ) goto enderr;
  287.               unless( Read(file,(UBYTE *)&bmhd,len) == len ) goto enderr;
  288.               bm->w = bmhd.w;
  289.               bm->h = bmhd.h;
  290.               bm->d = bmhd.nPlanes;
  291.               bm->wpl = ( (bmhd.w + 15) / 16 );
  292.               break;
  293.             }
  294.           case CMAP:
  295.             {
  296.               unless( loadCMAP(file,len,bm->cmap) ) goto enderr;
  297.               break;
  298.             }
  299.           case CAMG:
  300.             {
  301.               unless( Read(file,(UBYTE *)&bm->modes,4) == 4 ) goto enderr;
  302.               if (len > 4) Seek(file,(len-4),OFFSET_CURRENT);
  303.               break;
  304.             }
  305.           case BODY:
  306.             {
  307.               goto doBODY;
  308.             }
  309.           default:  /* skip unused chunk */
  310.             {
  311.               Seek(file,len,OFFSET_CURRENT);
  312.               break;
  313.             }
  314.         }
  315.  
  316.       if (len & 1) Seek(file,1,OFFSET_CURRENT);  /* odd sized chunk? */
  317.     }
  318.  
  319. doBODY:
  320.   unless( bmhd.w > 0 ) goto enderr;       /* no BMHD found? */
  321.   unless( (bmhd.compression == cmpNone)   /* cmpression we don't support? */
  322.   || (bmhd.compression == cmpByteRun1) ) goto enderr;
  323.   unless( loadBODY(file,len,&bmhd,bm) ) goto enderr;
  324.  
  325.   Close(file);
  326.  
  327.   return(bm);
  328. }
  329.  
  330.  
  331.  
  332. /*
  333. **  Free all memory associated with a BLITmap, including all bitplanes,
  334. **  the mask plane and the BLITmap structure itself.
  335. */
  336. void unloadILBM(struct BLITmap *bm)
  337. {
  338.   register int i;
  339.   if (bm)
  340.     {
  341.       for(i = 0; i < bm->d; i++)
  342.         {
  343.           if (bm->p[i]) FreeRaster(bm->p[i],bm->w,bm->h);
  344.         }
  345.       if (bm->m) FreeRaster(bm->m,bm->w,bm->h);
  346.       FreeMem(bm,sizeof(struct BLITmap));
  347.     }
  348. }
  349.  
  350.  
  351.  
  352. /*
  353. **  initialize a BitMap structure with info from a BLITmap structure
  354. */
  355. void BLITmap2BitMap(struct BLITmap *a, struct BitMap *b)
  356. {
  357.   register int i;
  358.   InitBitMap(b,a->d,a->w,a->h);
  359.   for(i = 0; i < a->d; i++) b->Planes[i] = a->p[i];
  360. }
  361.